#include "config.hpp"
#include <iostream>
#include <fstream>

bool Config::load_config(std::string filename)
{
    std::fstream fin(filename, std::ios::in);
    if(!fin.is_open())
    {
        std::cout << "Error: Can not open " << filename << ", load config failed!\n";
        return false;
    }
    while(!fin.eof())
    {
        std::string name;
        fin >> name;
        if(data.find(name) == data.end())
        {
            std::cout << "Error: Config term " << name << " not registered, load config failed!\n";
            return false;
        }
        auto &content = data[name];
        auto &type = content.v.type();
        bool type_found = false;

        if(type == typeid(glm::vec3))
        {
            content.load_state = load_vec3(fin, content.v);
            type_found = true;
        }
        if(type == typeid(std::string))
        {
            content.load_state = load_string(fin, content.v);
            type_found = true;
        }
        if(type == typeid(float))
        {
            content.load_state = load_float(fin, content.v);
            type_found = true;
        }

        if(!type_found)
        {
            std::cout << "Error: " << name << " has an invailed type, load config failed!\n";
            return false;
        }
        if(!content.load_state)
        {
            std::cout << "Error: load config failed due to previous error!\n";
            return false;
        }
    }
    for(auto key: keys)
    {
        if(!data[key].load_state)
        {
            std::cout << "Warning: Config " << key << " not loaded!\n";
        }
    }
    return true;
}

bool Config::load_vec3(std::fstream &fin, std::any &value) const
{
    auto &v = std::any_cast<glm::vec3&>(value);
    fin >> v.x >> v.y >> v.z;
    if(fin.fail())
    {
        std::cout << "Error: Failed to load vec3!\n";
        return false;
    }
    return true;
}

bool Config::load_string(std::fstream &fin, std::any &value) const
{
    auto &v = std::any_cast<std::string&>(value);
    fin >> v;
    if(fin.fail())
    {
        std::cout << "Error: Failed to load string!\n";
        return false;
    }
    return true;
}

bool Config::load_float(std::fstream &fin, std::any &value) const
{
    auto &v = std::any_cast<float&>(value);
    fin >> v;
    if(fin.fail())
    {
        std::cout << "Error: Failed to load float!\n";
        return false;
    }
    return true;
}

bool Config::is_all_loaded() const
{
    for(auto key: keys)
    {
        if(!data.find(key)->second.load_state)
        {
            return false;
        }
    }
    return true;
}